.\" ****************************************************************************
.\"  recorder_dump.3                                           recorder library
.\" ****************************************************************************
.\"
.\"   File Description:
.\"
.\"     Man page for the recorder library
.\"
.\"     This documents recorder_dump(3), recorder_dump_for(3), recorder_sort(3)
.\"
.\"
.\"
.\"
.\"
.\"
.\" ****************************************************************************
.\"  (C) 2019 Christophe de Dinechin <christophe@dinechin.org>
.\" %%%LICENSE_START(LGPLv2+_DOC_FULL)
.\" This is free documentation; you can redistribute it and/or
.\" modify it under the terms of the GNU Lesser General Public License as
.\" published by the Free Software Foundation; either version 2 of
.\" the License, or (at your option) any later version.
.\"
.\" The GNU Lesser General Public License's references to "object code"
.\" and "executables" are to be interpreted as the output of any
.\" document formatting or typesetting system, including
.\" intermediate and printed output.
.\"
.\" This manual is distributed in the hope that it will be useful,
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
.\" GNU Lesser General Public License for more details.
.\"
.\" You should have received a copy of the GNU General Public
.\" License along with this manual; if not, see
.\" <http://www.gnu.org/licenses/>.
.\" %%%LICENSE_END
.\" ****************************************************************************

.TH recorder_dump 3  "2019-03-09" "1.0" "Recorder Library"

.\" ----------------------------------------------------------------------------
.SH NAME
.\" ----------------------------------------------------------------------------
recorder_dump \- Dump all recorder entries
.br
recorder_dump_for \- Dump selected recorders
.br
recorder_sort \- Fine-controlled recorder dump
.br
recorder_dump_on_signal \- Dump the recorder when receiving a signal
.br
recorder_dump_on_common_signals \- Dump the recorder for standard signals


.\" ----------------------------------------------------------------------------
.SH SYNOPSIS
.\" ----------------------------------------------------------------------------
.nf
.B #include <recorder/recorder.h>
.PP
.BI "typedef unsigned (*recorder_show_fn) (const char *" text ","
.BI "                                      size_t" len ","
.BI "                                      void *" output ");"
.BI "typedef void (*recorder_format_fn)(recorder_show_fn " show ","
.BI "                                   void *" output ","
.BI "                                   const char * "label ","
.BI "                                   const char *" location ","
.BI "                                   uintptr_t" order ","
.BI "                                   uintptr_t" timestamp ","
.BI "                                   const char *" message ");"
.BI "typedef size_t (*recorder_type_fn)(intptr_t " trace ","
.BI "                                   const char *" format ","
.BI "                                   char *" buffer ","
.BI "                                   size_t" length ","
.BI "                                   uintptr_t" data ");"
.PP
.BI "unsigned recorder_dump(void);"
.BI "unsigned recorder_dump_for(const char *" pattern ");"
.BI "unsigned recorder_sort(const char *" pattern ","
.BI "                       recorder_format_fn " format ","
.BI "                       recorder_show_fn " show ","
.BI "                       void * " show_arg ");"
.BI "void recorder_dump_on_signal(int " signal ");"
.BI "void recorder_dump_on_common_signals(unsigned " add ","
.BI "                                     unsigned " remove ");"
.fi
.PP


.\" ----------------------------------------------------------------------------
.SH DESCRIPTION
.\" ----------------------------------------------------------------------------
.PP
The
.BR recorder_dump()
function dumps the content of all the event recorders, in the order in
which they were recorded. The
.BR recorder_dump_for()
function only dumps the recorders selected by the regular expression
.I pattern.
The
.BR recorder_sort()
function dumps the recorders selected by regular expression
.I pattern
using
.I format
to format an event record,
.I show
to show it, and passing
.I show_arg
to the function
.I show.

.PP
Calls to
.BR recorder_dump()
and
.BR recorder_dump_for()
are equivalents to calls to
.BR recorder_sort
where standard default values for
.I format,
.I show
and
.I arg.
These values can be changed using
.BR recorder_configure_format(3),
.BR recorder_configure_show(3)
and
.BR recorder_configure_output(3)
respectively.

.PP
The
.BR recorder_dump_on_signal()
function ensures that
.BR recorder_dump()
is called if the programs receives the given signal.
The
.BR recorder_dump_on_common_signals()
ensures that a recorder dump happens if any of a common set of
signals is received by the program (SIGQUIT, SIGILL, SIGABRT, SIGBUS,
SIGSEGV, SIGSYS, SIGXCPU, SIGXFSZ, SIGINFO, SIGUSR1, SIGUSR2,
SIGSTKFLT and SIGPWR, insofar as they are defined for the operating system).
The
.I add
and
.I remove
are bit masks that can be used to add or remove other signals compared
to the default list.


.\" ----------------------------------------------------------------------------
.SH RETURN VALUE
.\" ----------------------------------------------------------------------------
.PP
The
.BR recorder_dump(),
.BR recorder_dump_for()
and
.BR recorder_sort()
functions return the number of event records that were dumped.


.\" ----------------------------------------------------------------------------
.SH ENVIRONMENT VARIABLES
.\" ----------------------------------------------------------------------------
.PP
The
.BR recorder_dump_on_common_signals()
function also reads the following environment variables:

.TP
.B RECORDER_TRACES
A trace description, in the format expected by
.BR recorder_trace_set(3).

.TP
.B RECORDER_TWEAKS
Like RECORDER_TRACES, but normally used for tweaking configuration
values as opposed to tracing.

.TP
.B RECORDER_DUMP
Activates a background thread to dump the given pattern at regular intervals.


.\" ----------------------------------------------------------------------------
.SH EXAMPLES
.\" ----------------------------------------------------------------------------
.PP
The program below records its input arguments, and crashes if passed
.I crash
as the first command-line argument.
.PP
.in +4n
.EX
#include <recorder/recorder.h>
#include <string.h>

RECORDER(program_args, 32, "Program command-line arguments");
int main(int argc, char **argv)
{
    int a;
    recorder_dump_on_common_signals(0, 0);
    for (a = 0; a < argc; a++)
        record(program_args, "Argument %d is %+s", a, argv[a]);

    if (argc >= 2 && strcmp(argv[1], "crash") == 0)
    {
        char *ptr = NULL;
        strcpy(ptr, argv[1]);
    }
}
.EE
.in -4n
.PP
When a crash occurs, previously recorded events are printed out on the
console.

.PP
The program below is an instrumented version of the classical
recursive Fibonacci computation. It uses several recorders
corresponding to different types of events, and activates warnings and
errors in a way that can be configured by setting an environment variable.
.PP
.in +4n
.EX
#include <recorder/recorder.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

RECORDER(fib_main,    32, "Loops in fib function");
RECORDER(fib_loops,   32, "Loops in fib function");
RECORDER(fib_warning, 32, "Warnings in fib function");
RECORDER(fib_error,   32, "Errors in fib function");

int fib(int n)
{
    if (n <= 1) {
        if (n < 0)
            record(fib_error, "fib is undefined for negative value %d", n);
        return n;
    }
    record(fib_loops, "Computing fib(%d)", n);
    int result = fib(n-1) + fib(n-2);
    record(fib_loops, "Computed fib(%d) = %d", n, result);
    return result;
}

int main(int argc, char **argv)
{
    int a;
    recorder_dump_on_common_signals(0, 0);
    recorder_trace_set(".*_warning=35 .*_error");
    recorder_trace_set(getenv("FIB_TRACES"));
    for (a = 1; a < argc; a++) {
        int n = atoi(argv[a]);
        if (n >= RECORDER_TRACE(fib_warning))
            record(fib_warning, "Computing for %d may take a while", n);
        printf("fib(%d) = %d\n", n, fib(n));
        if (n >= RECORDER_TRACE(fib_warning))
            record(fib_warning, "Computation for %d finally completed", n);
    }
}
.EE
.in -4n
.PP
This program will produce an output similar to the following:
.PP
.in +4n
.EX
% fib 1 2 3 4 10 20 30 35 10 40 -1
fib(1) = 1
fib(2) = 1
fib(3) = 2
fib(4) = 3
fib(10) = 55
fib(20) = 6765
fib(30) = 832040
[2714667 0.177725] fib_warning: Computing for 35 may take a while
fib(35) = 9227465
[32575370 1.859156] fib_warning: Computation for 35 finally completed
fib(10) = 55
[32575547 1.859171] fib_warning: Computing for 40 may take a while
fib(40) = 102334155
[363735828 20.527882] fib_warning: Computation for 40 finally completed
[363735829 20.527887] fib_error: fib is undefined for negative value -1
fib(-1) = -1
.EE
.in -4n
The first column in trace outputs is the number of events that were
recorded. THe second column is the time in seconds since the program
started.

.PP
The same program can also be run with additional tracing or warnings,
for example:
.PP
.in +4n
.EX
% FIB_TRACES="recorder_location fib_loops fib_warning=3" /tmp/fib 3 4
/tmp/fib.c:33:[82 0.000496] fib_warning: Computing for 3 may take a while
/tmp/fib.c:18:[83 0.000561] fib_loops: Computing fib(3)
/tmp/fib.c:18:[84 0.000570] fib_loops: Computing fib(2)
/tmp/fib.c:20:[85 0.000575] fib_loops: Computed fib(2) = 1
/tmp/fib.c:20:[86 0.000581] fib_loops: Computed fib(3) = 2
fib(3) = 2
/tmp/fib.c:36:[87 0.000590] fib_warning: Computation for 3 finally completed
/tmp/fib.c:33:[88 0.000596] fib_warning: Computing for 4 may take a while
/tmp/fib.c:18:[89 0.000601] fib_loops: Computing fib(4)
/tmp/fib.c:18:[90 0.000607] fib_loops: Computing fib(3)
/tmp/fib.c:18:[91 0.000612] fib_loops: Computing fib(2)
/tmp/fib.c:20:[92 0.000619] fib_loops: Computed fib(2) = 1
/tmp/fib.c:20:[93 0.000625] fib_loops: Computed fib(3) = 2
/tmp/fib.c:18:[94 0.000664] fib_loops: Computing fib(2)
/tmp/fib.c:20:[95 0.000707] fib_loops: Computed fib(2) = 1
/tmp/fib.c:20:[96 0.000724] fib_loops: Computed fib(4) = 3
fib(4) = 3
/tmp/fib.c:36:[97 0.000741] fib_warning: Computation for 4 finally completed
.EE
.in -4n

.\" ----------------------------------------------------------------------------
.SH BUGS
.\" ----------------------------------------------------------------------------
.PP
The current signal handling mechanism does not yet use
.BR sigaltstack(2)
and consequently is not robust to stack overflow. It is also known to
fail for repeated signals. SIGINFO (and the associated Control-T
keyboard shortcut) do not exist on Linux, which is a pity.

.PP
Bugs should be reported using https://github.com/c3d/recorder/issues.


.\" ----------------------------------------------------------------------------
.SH SEE ALSO
.\" ----------------------------------------------------------------------------
.BR RECORDER_DEFINE (3),
.BR RECORDER_DECLARE (3)
.br
.BR recorder_dump (3),
.BR recorder_dump_for (3),
.br
.BR recorder_configure_output (3),
.BR recorder_configure_show (3)
.br
.BR recorder_configure_format (3),
.BR recorder_configure_type (3)

.PP
Additional documentation and tutorials can be found
at https://github.com/c3d/recorder.


.\" ----------------------------------------------------------------------------
.SH AUTHOR
.\" ----------------------------------------------------------------------------
Written by Christophe de Dinechin
